package es.udc.acs.consorcio.sesion;

import java.io.IOException;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.logging.Level;

import es.udc.acs.database.exception.ConexionInvalidaException;
import es.udc.acs.database.operations.DBConsorcioOperations;
import es.udc.acs.utils.GestorProperties;

public class Sesion implements Serializable{
	
	//Todos los atributos son privados y TODOS los metodos synchonized.
	private final String host;
	private final int port;
	private final String banco;
	private int reintegros = 0;
	private int abonos     = 0;
	private int traspasos  = 0;
	private volatile ArrayList<Canal> canales = new ArrayList<Canal>();
	private volatile SesionState state;
	
	public Sesion(String bancoSesion,String hostSesion, int portSesion, int numCanales){
		banco = bancoSesion;
		host  = hostSesion;
		port  = portSesion;
		state = new RecibirMensajes();
		
		int i;
	    for(i = 0; i<numCanales; i++) {
	    	canales.add(new Canal());
	    }
	}
	
	/*
	 * Devuelve nºcanal y nºmensaje ya concatenado 7 caracteres
	 * o ¿null? si hay algún problema
	 */
	public synchronized String sendMessage(String question){		
		return state.sendMessage(canales, question);
	}

	public synchronized String receiveMessage(String canal, String respuesta){
		return state.receiveMessage(canales, Integer.parseInt(canal), 
				Integer.parseInt(respuesta));
	}
	
	/*
	 * Métodos para mensajes de control
	 */
	public synchronized boolean detenerTrafico(){
		return state.detenerTrafico(this);
	}
	
	public synchronized boolean reanudarTrafico(){
		return state.reanudarTrafico(this);
	}
	
	public synchronized boolean cierreSesion(){
		return state.cierreSesion(this, canales, banco);
	}
	
	public synchronized boolean enRecuperacion(){
		if(state.enRecuperacion(this)){
			GestorProperties.getConsorcioLog().getLogger().
			log(Level.ALL, "<" + banco + "> Ejecutando la recuperacion");
			return state.recupera(this,canales);
		}
		return false;
	}
	
	public synchronized boolean finRecuperacion(){
		return state.finRecuperacion(this);
	}
	
	/*
	 * Visibilidad de paquete
	 * En caso de no poder guardar el estado recuperamos el estado anterior
	 */
	boolean setState(SesionState s) {
		
		SesionState aux = state;
		state = s;
		try {
		    DBConsorcioOperations.guardarSesionConsorcio(banco, this);
		    return true;
		} catch (Exception e) {
			state = aux;
			return false;
		}
	}
	
	public String getHost(){
		return host;
	}
	
	public int getPort(){
		return port;
	}
	
	public String getBanco(){
		return banco;
	}
	
	public synchronized void sumarReintegro() throws SQLException, 
													 IOException, 
													 ConexionInvalidaException {		
		reintegros++;
		DBConsorcioOperations.guardarSesionConsorcio(banco, this);
	}	
		
	public synchronized int obtenerReintegros() {	
		return reintegros;
	}
		
		
	public synchronized void sumarAbono() throws SQLException, 
												 IOException, 
												 ConexionInvalidaException {	
		abonos++;
		DBConsorcioOperations.guardarSesionConsorcio(banco, this);
	}	
		
	public synchronized int obtenerAbonos() {	
		return abonos;
	}
		
		
	public synchronized void sumarTraspaso() throws SQLException, 
													IOException, 
													ConexionInvalidaException {	
		traspasos++;
		DBConsorcioOperations.guardarSesionConsorcio(banco, this);
	}
		
		
	public synchronized int obtenerTraspasos() {	
		return traspasos;
	}
	
	public synchronized String obtenerEstado() {
		return state.obtenerEstado();
	}
	
	public synchronized String getResponseCanal(int canal){
		return canales.get(canal).getResponse();
	}
	
	public synchronized void mostrarCanales() {
		
		System.out.println("--------------------------------------------------------");
		System.out.println("Canales en la sesion que ha realizado la recuperacion");
		System.out.println("--------------------------------------------------------");

		for (Canal c : canales) {
			System.out.println("Libre: "+c.estaLibre()
									+" Nmensaje: "+c.obtenerNumMensaje()
									+" Nrespuesta: "+c.obtenerNumRespuesta()
									+" Question: "+c.getQuestion()
									+" Response: "+c.getResponse());
		}
		System.out.println("--------------------------------------------------------");
	}
}
